% figs2pdf Save several figures in 1 pdf file
%
% [] = figs2pdf(PDFFILE,[FIGLIST])
% 
% Save several figures in 1 pdf file with multiple pages.
%
% Inputs:
%	PDFFILE: the output pdf file name (without the pdf extension)
%	FIGLIST(optional): the list of figure's handle to include in the file
%		If not specified (default) save all open figures.
%
% Rq:
%	- To insert a blank page you can use an empty figure and insert it where you want.
%	- To insert text, create a invisible axes with your text.
%	- Eg:
%		t = 0:pi/50:10*pi;
%		f(1)=builtin('figure');set(gca,'visible','off');
%			text(.5,.5,sprintf('A list of figures from Matlab\nPDF TEST !'),'fontweight','bold','horizontalalignment','center','fontsize',16);
%		f(2)=figure;plot(t,cos(t));
%		f(3)=builtin('figure')
%		f(4)=figure;plot3(sin(t),cos(t),t);
%		figs2pdf('toto',f)
%
%	- This routine uses the ps2pdf.m script from Richard Quist:
%	http://www.mathworks.com/matlabcentral/fileexchange/19516-ps2pdf
%
% Created: 2010-04-02.
% Copyright (c) 2010, Guillaume Maze (Laboratoire de Physique des Oceans).
% All rights reserved.
% http://codes.guillaumemaze.org

% 
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
% 	* Redistributions of source code must retain the above copyright notice, this list of 
% 	conditions and the following disclaimer.
% 	* Redistributions in binary form must reproduce the above copyright notice, this list 
% 	of conditions and the following disclaimer in the documentation and/or other materials 
% 	provided with the distribution.
% 	* Neither the name of the Laboratoire de Physique des Oceans nor the names of its contributors may be used 
%	to endorse or promote products derived from this software without specific prior 
%	written permission.
%
% THIS SOFTWARE IS PROVIDED BY Guillaume Maze ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 
% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
% PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Guillaume Maze BE LIABLE FOR ANY 
% DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
% LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
% BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
% STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
% OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
%

function varargout = figs2pdf(varargin)

PDFFILE = 'figs'; % Default file name

epsname = '.figs2pdf.ps';

switch nargin
	case 0
		FIGLIST = findobj(0,'Type','figure');		
	case 1
		ar = varargin{1};
		switch class(ar)
			case 'char' % Provide name, retrieve figs list:
				PDFFILE = varargin{1};
				FIGLIST = findobj(0,'Type','figure');
				if isempty(FIGLIST)
					error('No figures currently available');
				end
			case 'double' % Provide fig list, retrieve name:
				figlist = varargin{1}; ii = 0;
				for ih = 1 : length(figlist)
					if ishandle(figlist(ih))
						if strcmp(get(figlist(ih),'type'),'figure')
							ii = ii + 1;
							FIGLIST(ii) = figlist(ih);
						else
							warning(sprintf('Handle #%i is not a figure !',figlist(ih)))
						end
					else
						warning(sprintf('%i is not a figure handle !',figlist(ih)))			
					end
				end% for ih
		end% switch 
	case 2
		PDFFILE = varargin{1};
		figlist = varargin{2}; ii = 0;
		for ih = 1 : length(figlist)
			if ishandle(figlist(ih))
				if strcmp(get(figlist(ih),'type'),'figure')
					ii = ii + 1;
					FIGLIST(ii) = figlist(ih);
				else
					warning(sprintf('Handle #%i is not a figure !',figlist(ih)))
				end
			else
				warning(sprintf('%i is not a figure handle !',figlist(ih)))			
			end
		end
end% switch 
PDFFILE = strrep(PDFFILE,'.pdf','');

%- Print each figure:
for ih = 1 : length(FIGLIST)
	if ih == 1
		eval(sprintf('print(''-dpsc2'',epsname,''-f%i'')',FIGLIST(ih)));
	else
		eval(sprintf('print(''-dpsc2'',''-append'',epsname,''-f%i'')',FIGLIST(ih)))
	end
end
%- Blend them in single pdf:
ps2pdf('psfile',epsname,'pdffile',sprintf('%s.pdf',PDFFILE),'deletepsfile',0,'gspapersize','a4');


disp(sprintf('Figure(s) [%s] printed in pdf file: %s.pdf\n!open %s.pdf',num2str(FIGLIST),PDFFILE,PDFFILE))

end %functionfigs2pdf




function ps2pdf(varargin)
%PS2PDF Function to convert a PostScript file to PDF using Ghostscript
%
%  Converts a postscript file into PDF. The resulting PDF file will contain
%  one page for each page defined in the postscript files, so a multi-page
%  postscript file, like those generated by using the '-append' option of 
%  MATLAB's print command, can be used to generate a multi-page PDF file. 
%
%   Ghostscript is a third-party application currently supplied with 
%   MATLAB. The caller may also specify a different version of Ghostscript
%   to use.
%
%   PS2PDF expects to be called with a set of parameter-value pairs. The
%   order of these is unimportant, but required parameters MUST be
%   specified
%
%   In the list below, required parameters are marked with an asterisk *
%   Parameter:        Value:  
%   *  psfile         full or relative path to the postscript file to convert
%
%   *  pdffile        full or relative path to the pdf file to create
%
%      gscommand      path to Ghostscript executable to use; this will try
%                     to default to the version of Ghostscript shipped with 
%                     MATLAB, if any. If this value is specified you should 
%                     also specify the gsfontpath and gslibpath values.
%
%      gsfontpath     full path to the Ghostscript font files
%                     If a gscommand is specified then this path should
%                     also be specified and reference the same Ghostscript
%                     version
%
%                     If gscommand is NOT specified and we can determine
%                     the version of Ghostscript, if any, shipped with
%                     MATLAB, then this value will be overridden to use the
%                     path that references MATLAB's version of Ghostscript
%
%      gslibpath      full path to the Ghostscript library (.ps) files. 
%                     If a gscommand is specified then this path should
%                     also be specified and reference the same Ghostscript
%                     version
%
%                     If gscommand is NOT specified and we can determine
%                     the version of Ghostscript, if any, shipped with
%                     MATLAB, then this value will be overridden to use the
%                     path that references MATLAB's version of Ghostscript
%
%      gspapersize    paper size to use in the created .pdf file. If not 
%                     specified or the specified value is not recognized 
%                     it will use whatever default paper size is 
%                     built into the version of Ghostscript being run
%
%                         NOTE: no scaling of the input occurs - it's simply
%                         placed on a page with the specified paper size. 
%
%                         Valid values for gspapersize are: 
%                              'letter', 'ledger', 'legal', '11x17', 
%                              'archA', 'archB', 'archC', 'archD', 'archE', 
%                              'a0', 'a1', 'a2', 'a3','a4', 'a5',
%                              'a6', 'a7', 'a8', 'a9', 'a10'
%                         
%      deletepsfile   0 to keep the input ps file after creating pdf
%                     non-zero to delete the input ps file after creating pdf
%                     Default is 0: keep the input ps file (do NOT delete it)
%                        NOTE: if the pdf creation process fails, the input
%                        PS file will be kept regardless of this setting
%
%      verbose        0 to suppress display of status/progress info; 
%                     non-zero to allow display of status/progress info
%                     Default is 0 (no display)
%
% Example usage: 
%    use MATLAB's version of Ghostscript to generate an A4 pdf file
%      ps2pdf('psfile', 'input.ps', 'pdffile', 'output.pdf', 'gspapersize', 'a4')
%
%    use a local copy of Ghostcript to generate a file, and display some 
%    status/progress info while doing so.
%      ps2pdf('psfile', '../reports/input.ps', 'pdffile', 'c:\temp\output3.pdf', ...
%            'gspapersize', 'a4', 'verbose', 1, ...)
%            'gscommand', 'C:\Program Files\GhostScript\bin\gswin32c.exe', ...
%            'gsfontpath', 'C:\Program Files\GhostScript\fonts', ...
%            'gslibpath', 'C:\Program Files\GhostScript\lib')
%
%    use MATLAB's version of Ghostscript to generate a pdf file and delete
%    the input.ps file when done 
%      ps2pdf('psfile', 'input.ps', 'pdffile', 'output.pdf', 'gspapersize', 'a4', 'deletepsfile', 1)

%   Update log: 
%      Aug 15, 2008: fixed bug where embedded space in location of 
%                    MATLAB's version of Ghostscript caused ps2pdf to fail.
%      Apr 16, 2008: added deletepsfile option

%   Copyright 2008 The MathWorks, Inc.

   if nargin < 1 
      error('ps2pdf:parameters', 'No parameters specified. Type ''help ps2pdf'' for details on how to use this function.');
   end

   % parse input args
   gsData = LocalParseArgs(varargin{:});

   % setup the file that tells GS what we want it to do
   gsData = LocalCreateResponseFile(gsData); 

   gsDebug = 0;
   if gsData.verbose 
      fprintf('ps2pdf: input settings are:\n');
      if isfield(gsData, 'paperSizes')
          gsData = rmfield(gsData, 'paperSizes');
      end
      gsData  %#ok<NOPRT>
      fprintf('ps2pdf: response file for Ghostscript is:\n');
      type(gsData.responseFile);
      gsDebug = 1;
   end

   %to hold results/status from system call
   s = 0; %#ok<NASGU>
   r = ''; %#ok<NASGU>

   % run Ghostscript to convert the file
   if gsData.useBuiltin 
      [s, r] = gsData.cmd(['@' gsData.responseFile], gsData.psFile, gsDebug);
   else 
      [s, r] = system([gsData.cmd ' @' gsData.responseFile ' ' gsData.psFile]);
   end

   if gsData.verbose
      disp( ['Ghostscript STDOUT: ' num2str(s) ] );
      disp( ['Ghostscript STDERR: ' r ] );
   else
      delete(gsData.responseFile)
   end

   if s && ~isempty(r)
      error('ps2pdf:ghostscript',  ['Problem converting PostScript. System returned error: ' num2str(s) '.' r]) 
   elseif s
      error('ps2pdf:ghostscript',  ['Problem calling GhostScript. System returned error: ' num2str(s)]) 
   end

   %if after all this we still couldn't create the file, report the error
   fid = fopen( gsData.pdfFile, 'r');
   if ( fid == -1 )
      error('ps2pdf:ghostscript', '%s', [ 'Ghostscript could not create ''' gsData.pfdFile '''.' ])
   else
      fclose( fid );
   end

   % if we get here, we successfully created pdf file; delete ps file if
   % requested to do so
   if gsData.deletePSFile 
       delete(gsData.psFile);
   end

end

%local function to parse arguments and fill in the gsData structure
%  .psFile - postscript file to convert
%  .pdfFile - pdf file to create
%  .cmd     - path/name of Ghostscript command to run or handle to gscript
%             builtin
%  .useBuiltin - 1 if using builtin gs command 
%  .fontPath - path to the Ghostscript fonts, if any
%  .libPath - path to the Ghostscript libs (Ghostscript .ps files), if any) 
%  .paperSize - paper size to set for resulting .pdf file 
%  .deletePSFile - 0 to keep (not delete) the input ps file if pdf created ok
%  .verbose - if non-zero, display some status/progress info to command window

function gsData = LocalParseArgs(varargin) 
    gsData.paperSizes = {'letter', 'ledger', 'legal', '11x17', 'archA', 'archB', ... 
                   'archC', 'archD', 'archE', 'a0', 'a1', 'a2', 'a3','a4', 'a5', ...
                   'a6', 'a7', 'a8', 'a9', 'a10'};

    %default values for some settings
    gsData.verbose      = 0; 
    gsData.useBuiltin   = 0;
    gsData.deletePSFile = 0; 
    
    for i = 1 : 2 : length(varargin)-1 
        param_arg = varargin{i};
        param_value = varargin{i+1};        
        switch(lower(param_arg)) 
            % path to ps file to conver
            case 'psfile'
               if ~exist(param_value, 'file')
                  error('print:ghostscript', ...
                      'Can not find postscript file <%s> to convert', ...
                      param_value)
               end
               gsData.psFile = param_value;

            % path to pdf file to create
            case 'pdffile'
                %verify we can create file at that location
                pdf_fid = fopen(param_value,'w');
                if pdf_fid < 0 
                    error('ps2pdf:invalidPDFFIle', ... 
                        'Can not open <%s> for writing', ...
                        param_value);
                end
                fclose(pdf_fid); 
                %delete temp file we created
                delete(param_value); 
                gsData.pdfFile = param_value;

            % full path to gs executable
            case 'gscommand' 
               if ~exist(param_value, 'file')
                  error('ps2pdf:ghostscriptCommand', ...
                      'Can not find Ghostscript executable (''gscommand'') <%s>',...
                      param_value)
               end
               if ispc && ~isempty(findstr(param_value, ' '))
                   param_value = ['"' param_value '"']; %#ok<AGROW>
               end
               gsData.cmd = param_value; 
                
            % full path to gs font dir
            case 'gsfontpath' 
               if ~exist(param_value, 'dir')
                   error('ps2pdf:ghostscriptFontPath', ...
                         'Can not find the directory <%s> for Ghostscript fonts (''gsfontpath'')', ...
                         param_value)
               end
               gsData.fontPath = param_value;

            % full path to gs lib dir
            case 'gslibpath' 
               if ~exist(param_value, 'dir')
                   error('ps2pdf:ghostscriptLibPath', ...
                         'Can not find the directory <%s> for Ghostscript library files (''gslibpath'')', ...
                         param_value)
               end
               gsData.libPath = param_value;
                
            % paper size 
            case 'gspapersize'
               idx = strcmpi(param_value, gsData.paperSizes);
               if ~any(idx)
                  warning('ps2pdf:papersize', ...
                        '''gspapersize'' value <%s> not found in the list of known sizes, ignoring it.', param_value);
               else
                  gsData.paperSize = gsData.paperSizes{idx};
               end

            % deletePSFile
            case 'deletepsfile'
               if isnumeric(param_value) 
                  gsData.deletePSFile = param_value; 
               else
                   warning('ps2pdf:deletepsfile', ...
                         '''deletepsfile'' value <%s> class <%s> should be numeric, defaulting to 0', ...
                         param_value, class(param_value));
               end
               
            % verbose
            case 'verbose'
               if isnumeric(param_value) 
                  gsData.verbose = param_value; 
               else
                   warning('ps2pdf:verbose', ...
                         '''verbose'' value <%s> class <%s> should be numeric, defaulting to 0', ...
                         param_value, class(param_value));
               end
               
            otherwise
               if isnumeric(param_value)
                   param_value = num2str(param_value);
               end
                  warning('ps2pdf:unknown', ...
                     'ignoring unknown parameter <%s> with value <%s>.', param_arg, param_value);
        end
    end    

    if ~isfield(gsData, 'psFile') 
        error('ps2pdf:noInputFile', ...
               'No input (psfile) file specified');
    end
    
    if ~isfield(gsData, 'pdfFile') 
        error('ps2pdf:noOutputFile', ...
               'No output (pdffile) file specified');
    end
    
    if ~isfield(gsData, 'cmd') 
        
        v = ver('MATLAB');
		v.Version = strread(v.Version,'%s','delimiter','.');
%        if str2double(v.Version) < 7.4 %% Does not work after 7.10 version !
        if str2double(v.Version{2}) < 4
            [gsCmd, ghostDir] = Local_GetOldGhostscript();
            gsData.cmd = gsCmd;
        else 
            % version 7.4 or later
           % the path to Ghostscript changed in 7a
           ghostDir = fullfile( matlabroot, 'sys', 'gs8x' );
           if ~exist(ghostDir, 'dir')
              error('ps2pdf:ghostscriptCommand', ...
                    'Can not find Ghostscript installed with MATLAB in <%s>',...
                    ghostDir);
           end
           gsData.cmd = Local_GetGscriptFcnHandle;
           if ~isempty(gsData.cmd)
              gsData.useBuiltin = 1; % use builtin Ghostscript
           end
        end
        
        if ~isempty(gsData.cmd)
           % if using MATLAB's version of GhostScript, use same set of fonts and library files
           if isfield(gsData, 'fontPath') || isfield(gsData, 'libPath')
              warning('ps2pdf:ghostscriptPathOverride', ...
                    'Using MATLAB''s version of Ghostscript; overriding ''gsfontpath'' and ''gslibpath'' to use builtin MATLAB version');
           end
           gsData.fontPath = fullfile( ghostDir, 'fonts', '');
           gsData.libPath = fullfile( ghostDir, 'ps_files', '');
        else 
            error('ps2pdf:noGhostscriptCommand', ...
                  'Can not find Ghostscript program in MATLAB');
        end
    else
        % if gscommandpath was specified, 
        if ~isfield(gsData, 'fontPath') || ~isfield(gsData, 'libPath')
           warning('ps2pdf:ghostscriptCommandSuggestion', ...
                 ['When specifying a Ghostscript executable (''gscommand'') you should also '...
                 'specify both the ''gsfontpath'' and ''gslibpath'' locations']);
   
        end
    end
end

%local function to create the input file needed for Ghostscript
function gsData = LocalCreateResponseFile(gsData) 
   % open a response file to write out Ghostscript commands
   rsp_file = [tempname '.rsp'];
   rsp_fid = fopen (rsp_file, 'w');

   if (rsp_fid < 0)
      error('ps2pdf:responseFileCreate', 'Unable to create response file')
   end

   fprintf(rsp_fid, '-dBATCH -dNOPAUSE\n');
   if ~gsData.verbose
       fprintf(rsp_fid, '-q\n');
   end
   if isfield(gsData, 'libPath')
      fprintf(rsp_fid, '-I"%s"\n', gsData.libPath);
   end
   if isfield(gsData, 'fontPath')
      fprintf(rsp_fid, '-I"%s"\n', gsData.fontPath);
   end
   if isfield(gsData, 'paperSize') 
      fprintf( rsp_fid, '-sPAPERSIZE=%s\n', gsData.paperSize );
   end
   fprintf(rsp_fid, '-sOutputFile="%s"\n', gsData.pdfFile);
   fprintf(rsp_fid, '-sDEVICE=%s\n', 'pdfwrite');
   fclose(rsp_fid);
   gsData.responseFile = rsp_file;
end

%local function to get a handle to MATLAB's Ghostscript implementation
%NOTE: this may change or be removed in future releases
function gs = Local_GetGscriptFcnHandle()
  gs = '';
  p = which('-all', 'gscript');
  if ~isempty(p) 
      p = p{1};
      fpath = fileparts(p);
      olddir = cd(fpath);
      gs = @gscript;
      cd(olddir);
  end
end

% local function to try and get location of Ghostscript in older MATLAB
function [gsCmd, ghostDir] = Local_GetOldGhostscript
   ghostDir = fullfile( matlabroot, 'sys', 'ghostscript' );
   gsCmd = '';
   if ispc
      if exist(fullfile(ghostDir,'bin','win32','gs.exe'), 'file')
         gsCmd = fullfile(ghostDir,'bin','win32','gs.exe');
      end
   else 
      if exist(fullfile(ghostDir,'bin',lower(computer),'gs'), 'file')
         gsCmd = fullfile(ghostDir,'bin',lower(computer), 'gs');
      end
   end
   gsCmd = ['"' gsCmd '"'];
end




